package com.xiyuan.smartutils;

import com.xiyuan.smartutils.constants.SignConstants;
import com.xiyuan.smartutils.math.Calculator;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiyuan.smartutils.constants.SignConstants.KiB;

/**
 * 数字工具类<br>
 * 对于精确值计算应该使用 {@link BigDecimal}<br>
 * JDK7中<strong>BigDecimal(double val)</strong>构造方法的结果有一定的不可预知性，例如：
 *
 * <pre>
 * new BigDecimal(0.1)
 * </pre>
 * <p>
 * 表示的不是<strong>0.1</strong>而是<strong>0.1000000000000000055511151231257827021181583404541015625</strong>
 *
 * <p>
 * 这是因为0.1无法准确的表示为double。因此应该使用<strong>new BigDecimal(String)</strong>。
 * </p>
 * 相关介绍：
 * <ul>
 * <li><a href="http://www.oschina.net/code/snippet_563112_25237">http://www.oschina.net/code/snippet_563112_25237</a></li>
 * <li><a href="https://github.com/venusdrogon/feilong-core/wiki/one-jdk7-bug-thinking">https://github.com/venusdrogon/feilong-core/wiki/one-jdk7-bug-thinking</a></li>
 * </ul>
 *
 * @author xiyuan-lgz 2024-02-15 @version v1.0.0 新建与整理
 */
@SuppressWarnings("ALL")
public class Numbers implements SignConstants {
    private static Map<String, Long> SIZE_UNIT_CONF = new HashMap<>();
    
    static {
        SIZE_UNIT_CONF.put("k", 1L * KiB);
        SIZE_UNIT_CONF.put("kb", 1L * KiB);
        SIZE_UNIT_CONF.put("kib", 1L * KiB);
        SIZE_UNIT_CONF.put("m", 1L * MiB);
        SIZE_UNIT_CONF.put("mb", 1L * MiB);
        SIZE_UNIT_CONF.put("mib", 1L * MiB);
        SIZE_UNIT_CONF.put("g", 1L * GiB);
        SIZE_UNIT_CONF.put("gb", 1L * GiB);
        SIZE_UNIT_CONF.put("gib", 1L * GiB);
        SIZE_UNIT_CONF.put("t", 1L * TiB);
        SIZE_UNIT_CONF.put("tb", 1L * TiB);
        SIZE_UNIT_CONF.put("tib", 1L * TiB);
        SIZE_UNIT_CONF.put("p", 1L * PiB);
        SIZE_UNIT_CONF.put("pb", 1L * PiB);
        SIZE_UNIT_CONF.put("pib", 1L * PiB);
    }
    
    // 圆
    private static final char YUAN_CN = '\u5706';
    
    // 整
    private static final char SD_CN = '\u6574';
    
    
    // 点
    private static final char DOT_CN = '\u70b9';
    
    // 负
    private static final char NEG_CN = '\u8d1f';
    
    
    // 零壹贰叁肆伍陆柒捌玖
    private static final char[] _RMB_CN_ = "\u96f6\u58f9\u8d30\u53c1\u8086\u4f0d\u9646\u67d2\u634c\u7396".toCharArray();
    
    private static final char[] _NUM_CN_ = "\u96f6\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d".toCharArray();
    
    // {'0', 拾佰仟}
    private static final char[] U1_RMB = ("\u0000" + "\u62fe\u4f70\u4edf").toCharArray();
    
    // {0, 十百千}
    private static final char[] U1_NUM = ("\u0000" + "\u5341\u767e\u5343").toCharArray();
    
    // 0万亿兆京垓秭穰沟涧正载极
    private static final char[] U2 = ("\u0000" + "\u4e07\u4ebf\u5146\u4eac\u5793\u79ed\u7a70\u6c9f\u6da7\u6b63\u8f7d\u6781").toCharArray();
    // 分厘毫丝忽微纤沙尘埃渺
    private static final String NUM_DEC_STR = "\u5206\u5398\u6beb\u4e1d\u5ffd\u5fae\u7ea4\u6c99\u5c18\u57c3\u6e3a";
    private static final char[] NUM_DEC_UNIT = NUM_DEC_STR.toCharArray();
    private static final char[] RMB_DEC_UNIT = ("\u89d2" + NUM_DEC_STR).toCharArray();
    /**
     * 小数点长度比对
     */
    private static Long[] RDXL;
    
    /**
     * 默认除法运算精度
     */
    private static final int DEFAULT_DIV_SCALE = 10;
    
    /**
     * 0-20对应的阶乘，超过20的阶乘会超过Long.MAX_VALUE
     */
    private static final long[] FACTORIALS = new long[]{
            1L, 1L, 2L, 6L, 24L, 120L, 720L, 5040L, 40320L, 362880L, 3628800L, 39916800L, 479001600L, 6227020800L,
            87178291200L, 1307674368000L, 20922789888000L, 355687428096000L, 6402373705728000L, 121645100408832000L,
            2432902008176640000L};
    
    static {
        int len = Math.max(NUM_DEC_UNIT.length, RMB_DEC_UNIT.length);
        List<Long> ls = new ArrayList<Long>();
        for (int i = 1; i <= len; i++) {ls.add(Long.parseLong(StrUtils.fixedLen(1L, i, '0', false)));}
        RDXL = ls.toArray(new Long[0]);
    }
    
    
    private static int appendDec(long dec, boolean isAmount, char[] val, int offset, int radixLength, char[] CHS_CN,
                                 char[] DEC_UNIT) {
        if (dec == 0 && isAmount) {val[--offset] = SD_CN;}
        else {
            long left = dec;
            boolean zo = false, o = false, ns = false;
            int s = radixLength - 1;
            for (int i = s; i > -1; i--, s--) {
                if (left == 0) break;
                o = true;
                long f = left % 10;
                left = left / 10;
                
                if (f == 0 && !ns) continue;
                ns = true;
                // 非金额
                if (!isAmount) {
                    val[--offset] = CHS_CN[(int) f];
                    continue;
                }
                
                boolean flag = false;
                if (f > 0) {
                    val[--offset] = DEC_UNIT[i];
                    val[--offset] = CHS_CN[(int) f];
                    flag = true;
                }
                if (left >= 10) {
                    if (left % 10 == 0 && !zo) {
                        val[--offset] = CHS_CN[0];
                        zo = true;
                    }
                    flag = true;
                }
                else if (!flag) {
                    flag = true;
                    val[--offset] = DEC_UNIT[i];
                    val[--offset] = CHS_CN[(int) left];
                }
                
            }
            if (o && s > -1 && val[offset] != CHS_CN[0]) {
                while (s > -1) {
                    val[--offset] = CHS_CN[0];
                    s--;
                    if (isAmount) break;// 金额模式 多个 0 只需要一个即可
                }
            }
            if (o && !isAmount) val[--offset] = DOT_CN;// 非 金额模式需要 加'点'
        }
        
        return offset;
    }
    
    private static int appendInteger(String numText, char[] val, int offset, char[] CHS_CN, boolean isAmount) {
        char[] U1 = (isAmount ? U1_RMB : U1_NUM);
        // 从各位开始计算
        int len = 0;
        int limit = numText.length();
        char u2 = 0;
        boolean zero = false, zeroCanBeStart = false;
        for (int i = limit - 1; i >= 0; i--, len++) {
            int n = numText.charAt(i) - 48;
            char ch = CHS_CN[n];
            
            // 计算[万]或者[亿]
            int u2idx = len / 4;
            if (u2idx > U2.length - 1) {
                throw new IllegalArgumentException("数据值超出最大值: " + U1[U1.length - 1] + U2[U2.length - 1]);
            }
            if (len % 4 == 0) {u2 = U2[u2idx];}
            // 计算[拾]、[佰]或[仟]
            char u1 = U1[len % 4];
            if (n == 0) {
                if (zeroCanBeStart) {zero = true;}
                continue;
            }
            
            // 插入零
            if (zero) {
                if (zeroCanBeStart) {
                    val[--offset] = CHS_CN[0];
                    zeroCanBeStart = false;
                }
                zero = false;
                
            }
            else {
                // 允许开始插入0
                zeroCanBeStart = true;
            }
            
            // 插入[万]或者[亿]
            if (u2 != 0) {
                if (u2idx == 3) {//'兆'
                    // val[--offset] = U2[2];
                    u2 = U2[1];
                }
                
                val[--offset] = u2;
                u2 = 0;
            }
            
            // 插入[拾]、[佰]或[仟]
            if (u1 != 0) {val[--offset] = u1;}
            
            // 插入数字
            val[--offset] = ch;
        }
        
        return offset;
    }
    
    /**
     * 奖金额转换成中文
     *
     * @param value       金额数值
     * @param radixLength 小数点长度。
     * @param isAmount    是否为金额模式。
     * @return 中文金额
     * @throws IllegalArgumentException 异常信息；如果 小数点长度不符合规范或者超出最大最大内容长度则抛出异常
     */
    public static String toChinese(BigInteger value, int radixLength, boolean isAmount) {
        if (value == null) return null;
        if (radixLength < 0 || radixLength > (isAmount ? RMB_DEC_UNIT : NUM_DEC_UNIT).length) {
            throw new IllegalArgumentException("Invalid radixLength:" + radixLength);
        }
        
        BigInteger bi = value;
        boolean neg = value.compareTo(BigInteger.ZERO) < 0;
        if (neg) bi = bi.multiply(new BigInteger("-1"));
        // RMB_DEC.length;
        BigInteger unit_l = BigInteger.valueOf(RDXL[radixLength]);
        BigInteger num = bi.divide(unit_l);
        long dec = bi.mod(unit_l).longValue();
        String numText = num.toString();
        char[] val = new char[Math.max(numText.length() * 3, 64)];
        char[] DEC_UNIT = (isAmount ? RMB_DEC_UNIT : NUM_DEC_UNIT);
        char[] CHS_CN = (isAmount ? _RMB_CN_ : _NUM_CN_);
        
        // 添加小数点
        int offset = appendDec(dec, isAmount, val, val.length, radixLength, CHS_CN, DEC_UNIT);
        
        // 插入标准单位
        boolean dot = val[val.length - 1] != 0;
        int cpzo = num.compareTo(BigInteger.ZERO);
        if (cpzo > 0 && isAmount) {val[--offset] = YUAN_CN;}
        
        // 插入 整形
        if (cpzo == 0) {
            if (isAmount && val[offset] == CHS_CN[0]) {
                val[offset] = 0;
                offset++;
            }
            else if (!isAmount) {
                val[--offset] = CHS_CN[0];
            }
        }
        else {
            offset = appendInteger(numText, val, offset, CHS_CN, isAmount);
        }
        
        if (neg) val[--offset] = NEG_CN;
        int count = val.length - offset;
        return count == 0 ? "" : new String(val, offset, count);
    }
    
    public static String toChinese(BigInteger value, boolean isAmount) {
        return toChinese(value, 0, isAmount);
    }
    
    public static String toChinese(BigInteger value) {
        return toChinese(value, 0, false);
    }
    
    public static String toChinese(BigInteger value, int radixLen) {
        return toChinese(value, radixLen, false);
    }
    
    
    public static String toChinese(Long value) {
        return toChinese(value, 0, false);
    }
    
    public static String toChinese(Long value, boolean isAmount) {
        return toChinese(value, 0, isAmount);
    }
    
    public static String toChinese(Long value, int radixLength) {
        return toChinese(value, radixLength, false);
    }
    
    public static String toChinese(Long value, int radixLength, boolean isAmount) {
        return toChinese(value == null ? null : BigInteger.valueOf(value), radixLength, isAmount);
    }
    
    
    public static String toChinese(long value) {
        return toChinese(value, 0, false);
    }
    
    public static String toChinese(long value, boolean isAmount) {
        return toChinese(value, 0, isAmount);
    }
    
    public static String toChinese(long value, int radixLength) {
        return toChinese(value, radixLength, false);
    }
    
    public static String toChinese(long value, int radixLength, boolean isAmount) {
        return toChinese(BigInteger.valueOf(value), radixLength, isAmount);
    }
    
    
    private static int getScaleLen(BigDecimal b, boolean isAmount) {
        if (b == null) return 0;
        return b.setScale((isAmount ? RMB_DEC_UNIT : NUM_DEC_UNIT).length, RoundingMode.FLOOR)
                .stripTrailingZeros()
                .scale();
    }
    
    public static String toChinese(double value, int radixLength, boolean isAmount) {
        return toChinese(BigDecimal.valueOf(value), radixLength, isAmount);
    }
    
    public static String toChinese(double value, int radixLength) {
        return toChinese(BigDecimal.valueOf(value), radixLength, false);
    }
    
    public static String toChinese(double value, boolean isAmount) {
        BigDecimal b = BigDecimal.valueOf(value);
        return toChinese(b, getScaleLen(b, isAmount), isAmount);
    }
    
    public static String toChinese(Double value, int radixLength, boolean isAmount) {
        return value == null ? null : toChinese(BigDecimal.valueOf(value), radixLength, isAmount);
    }
    
    public static String toChinese(Double value, int radixLength) {
        return value == null ? null : toChinese(BigDecimal.valueOf(value), radixLength, false);
    }
    
    public static String toChinese(Double value, boolean isAmount) {
        BigDecimal b = value == null ? null : BigDecimal.valueOf(value);
        return value == null ? null : toChinese(BigDecimal.valueOf(value), getScaleLen(b, isAmount), isAmount);
    }
    
    public static String toChinese(BigDecimal value, boolean isAmount) {
        return toChinese(value, getScaleLen(value, isAmount), isAmount);
    }
    
    public static String toChinese(BigDecimal value, int radixLength) {
        return toChinese(value, radixLength, false);
    }
    
    /**
     * @param value
     * @param radixLength
     * @param isAmount
     * @return
     */
    public static String toChinese(BigDecimal value, int radixLength, boolean isAmount) {
        if (value == null) return null;
        if (radixLength < 0 || radixLength > (isAmount ? RMB_DEC_UNIT : NUM_DEC_UNIT).length) {
            throw new IllegalArgumentException("Invalid radixLength:" + radixLength);
        }
        
        BigInteger b = value.setScale(radixLength, RoundingMode.FLOOR)
                .stripTrailingZeros()
                .multiply(BigDecimal.valueOf(RDXL[radixLength]))
                .setScale(0, RoundingMode.FLOOR)
                .toBigInteger();
        
        
        return toChinese(b, radixLength, isAmount);
    }
    
    
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static double add(float v1, float v2) {
        return add(Float.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static double add(float v1, double v2) {
        return add(Float.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static double add(double v1, float v2) {
        return add(Double.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static double add(double v1, double v2) {
        return add(Double.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的加法运算
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static double add(Double v1, Double v2) {
        //noinspection RedundantCast
        return add((Number) v1, (Number) v2).doubleValue();
    }
    
    /**
     * 提供精确的加法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param v1 被加数
     * @param v2 加数
     * @return 和
     */
    public static BigDecimal add(Number v1, Number v2) {
        return add(new Number[]{v1, v2});
    }
    
    /**
     * 提供精确的加法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被加值
     * @return 和
     */
    public static BigDecimal add(Number... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        Number value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.add(toBigDecimal(value));
            }
        }
        return result;
    }
    
    /**
     * 提供精确的加法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被加值
     * @return 和
     */
    public static BigDecimal add(String... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        String value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (StrUtils.isNotBlank(value)) {
                result = result.add(toBigDecimal(value));
            }
        }
        return result;
    }
    
    /**
     * 提供精确的加法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被加值
     * @return 和
     */
    public static BigDecimal add(BigDecimal... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.add(value);
            }
        }
        return result;
    }
    
    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static double sub(float v1, float v2) {
        return sub(Float.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static double sub(float v1, double v2) {
        return sub(Float.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static double sub(double v1, float v2) {
        return sub(Double.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static double sub(double v1, double v2) {
        return sub(Double.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static double sub(Double v1, Double v2) {
        //noinspection RedundantCast
        return sub((Number) v1, (Number) v2).doubleValue();
    }
    
    /**
     * 提供精确的减法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 差
     */
    public static BigDecimal sub(Number v1, Number v2) {
        return sub(new Number[]{v1, v2});
    }
    
    /**
     * 提供精确的减法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被减值
     * @return 差
     */
    public static BigDecimal sub(Number... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        Number value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.subtract(toBigDecimal(value));
            }
        }
        return result;
    }
    
    /**
     * 提供精确的减法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被减值
     * @return 差
     */
    public static BigDecimal sub(String... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        String value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (StrUtils.isNotBlank(value)) {
                result = result.subtract(toBigDecimal(value));
            }
        }
        return result;
    }
    
    /**
     * 提供精确的减法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被减值
     * @return 差
     */
    public static BigDecimal sub(BigDecimal... values) {
        if (Arrays.isEmpty(values)) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal value = values[0];
        BigDecimal result = toBigDecimal(value);
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            if (null != value) {
                result = result.subtract(value);
            }
        }
        return result;
    }
    
    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static double mul(float v1, float v2) {
        return mul(Float.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static double mul(float v1, double v2) {
        return mul(Float.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static double mul(double v1, float v2) {
        return mul(Double.toString(v1), Float.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static double mul(double v1, double v2) {
        return mul(Double.toString(v1), Double.toString(v2)).doubleValue();
    }
    
    /**
     * 提供精确的乘法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static double mul(Double v1, Double v2) {
        //noinspection RedundantCast
        return mul((Number) v1, (Number) v2).doubleValue();
    }
    
    /**
     * 提供精确的乘法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static BigDecimal mul(Number v1, Number v2) {
        return mul(new Number[]{v1, v2});
    }
    
    /**
     * 提供精确的乘法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被乘值
     * @return 积
     */
    public static BigDecimal mul(Number... values) {
        if (Arrays.isEmpty(values) || Arrays.hasNull(values)) {
            return BigDecimal.ZERO;
        }
        
        Number value = values[0];
        BigDecimal result = new BigDecimal(value.toString());
        for (int i = 1; i < values.length; i++) {
            value = values[i];
            result = result.multiply(new BigDecimal(value.toString()));
        }
        return result;
    }
    
    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 积
     */
    public static BigDecimal mul(String v1, String v2) {
        return mul(new BigDecimal(v1), new BigDecimal(v2));
    }
    
    /**
     * 提供精确的乘法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被乘值
     * @return 积
     */
    public static BigDecimal mul(String... values) {
        if (Arrays.isEmpty(values) || Arrays.hasNull(values)) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal result = new BigDecimal(values[0]);
        for (int i = 1; i < values.length; i++) {
            result = result.multiply(new BigDecimal(values[i]));
        }
        
        return result;
    }
    
    /**
     * 提供精确的乘法运算<br>
     * 如果传入多个值为null或者空，则返回0
     *
     * @param values 多个被乘值
     * @return 积
     */
    public static BigDecimal mul(BigDecimal... values) {
        if (Arrays.isEmpty(values) || Arrays.hasNull(values)) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal result = values[0];
        for (int i = 1; i < values.length; i++) {
            result = result.multiply(values[i]);
        }
        return result;
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(float v1, float v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(float v1, double v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, float v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1, double v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(Double v1, Double v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static BigDecimal div(Number v1, Number v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况的时候,精确到小数点后10位,后面的四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static BigDecimal div(String v1, String v2) {
        return div(v1, v2, DEFAULT_DIV_SCALE);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static double div(float v1, float v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static double div(float v1, double v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static double div(double v1, float v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static double div(Double v1, Double v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static BigDecimal div(Number v1, Number v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度,后面的四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 精确度，如果为负值，取绝对值
     * @return 两个参数的商
     */
    public static BigDecimal div(String v1, String v2, int scale) {
        return div(v1, v2, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static double div(float v1, float v2, int scale, RoundingMode roundingMode) {
        return div(Float.toString(v1), Float.toString(v2), scale, roundingMode).doubleValue();
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static double div(float v1, double v2, int scale, RoundingMode roundingMode) {
        return div(Float.toString(v1), Double.toString(v2), scale, roundingMode).doubleValue();
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static double div(double v1, float v2, int scale, RoundingMode roundingMode) {
        return div(Double.toString(v1), Float.toString(v2), scale, roundingMode).doubleValue();
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale, RoundingMode roundingMode) {
        return div(Double.toString(v1), Double.toString(v2), scale, roundingMode).doubleValue();
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static double div(Double v1, Double v2, int scale, RoundingMode roundingMode) {
        //noinspection RedundantCast
        return div((Number) v1, (Number) v2, scale, roundingMode).doubleValue();
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static BigDecimal div(Number v1, Number v2, int scale, RoundingMode roundingMode) {
        if (v1 instanceof BigDecimal && v2 instanceof BigDecimal) {
            return div((BigDecimal) v1, (BigDecimal) v2, scale, roundingMode);
        }
        return div(StrUtils.toStringOrNull(v1), StrUtils.toStringOrNull(v2), scale, roundingMode);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static BigDecimal div(String v1, String v2, int scale, RoundingMode roundingMode) {
        return div(toBigDecimal(v1), toBigDecimal(v2), scale, roundingMode);
    }
    
    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,由scale指定精确度
     *
     * @param v1           被除数
     * @param v2           除数
     * @param scale        精确度，如果为负值，取绝对值
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 两个参数的商
     */
    public static BigDecimal div(BigDecimal v1, BigDecimal v2, int scale, RoundingMode roundingMode) {
        Asserts.nonNull(v2, "Divisor must be not null !");
        if (null == v1) {
            return BigDecimal.ZERO;
        }
        if (scale < 0) {
            scale = -scale;
        }
        return v1.divide(v2, scale, roundingMode);
    }
    
    /**
     * 补充Math.ceilDiv() JDK8中添加了和Math.floorDiv()但却没有ceilDiv()
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static int ceilDiv(int v1, int v2) {
        return (int) Math.ceil((double) v1 / v2);
    }
    
    // ------------------------------------------------------------------------------------------- round
    
    /**
     * 保留固定位数小数<br>
     * 采用四舍五入策略 {@link RoundingMode#HALF_UP}<br>
     * 例如保留2位小数：123.456789 =》 123.46
     *
     * @param v     值
     * @param scale 保留小数位数
     * @return 新值
     */
    public static BigDecimal round(double v, int scale) {
        return round(v, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 保留固定位数小数<br>
     * 采用四舍五入策略 {@link RoundingMode#HALF_UP}<br>
     * 例如保留2位小数：123.456789 =》 123.46
     *
     * @param v     值
     * @param scale 保留小数位数
     * @return 新值
     */
    public static String roundStr(double v, int scale) {
        return round(v, scale).toPlainString();
    }
    
    /**
     * 保留固定位数小数<br>
     * 采用四舍五入策略 {@link RoundingMode#HALF_UP}<br>
     * 例如保留2位小数：123.456789 =》 123.46
     *
     * @param numberStr 数字值的字符串表现形式
     * @param scale     保留小数位数
     * @return 新值
     */
    public static BigDecimal round(String numberStr, int scale) {
        return round(numberStr, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 保留固定位数小数<br>
     * 采用四舍五入策略 {@link RoundingMode#HALF_UP}<br>
     * 例如保留2位小数：123.456789 =》 123.46
     *
     * @param number 数字值
     * @param scale  保留小数位数
     * @return 新值
     */
    public static BigDecimal round(BigDecimal number, int scale) {
        return round(number, scale, RoundingMode.HALF_UP);
    }
    
    /**
     * 保留固定位数小数<br>
     * 采用四舍五入策略 {@link RoundingMode#HALF_UP}<br>
     * 例如保留2位小数：123.456789 =》 123.46
     *
     * @param numberStr 数字值的字符串表现形式
     * @param scale     保留小数位数
     * @return 新值
     */
    public static String roundStr(String numberStr, int scale) {
        return round(numberStr, scale).toPlainString();
    }
    
    /**
     * 保留固定位数小数<br>
     * 例如保留四位小数：123.456789 =》 123.4567
     *
     * @param v            值
     * @param scale        保留小数位数
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 新值
     */
    public static BigDecimal round(double v, int scale, RoundingMode roundingMode) {
        return round(Double.toString(v), scale, roundingMode);
    }
    
    /**
     * 保留固定位数小数<br>
     * 例如保留四位小数：123.456789 =》 123.4567
     *
     * @param v            值
     * @param scale        保留小数位数
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 新值
     */
    public static String roundStr(double v, int scale, RoundingMode roundingMode) {
        return round(v, scale, roundingMode).toPlainString();
    }
    
    /**
     * 保留固定位数小数<br>
     * 例如保留四位小数：123.456789 =》 123.4567
     *
     * @param numberStr    数字值的字符串表现形式
     * @param scale        保留小数位数，如果传入小于0，则默认0
     * @param roundingMode 保留小数的模式 {@link RoundingMode}，如果传入null则默认四舍五入
     * @return 新值
     */
    public static BigDecimal round(String numberStr, int scale, RoundingMode roundingMode) {
        Asserts.nonBlank(numberStr);
        if (scale < 0) {
            scale = 0;
        }
        return round(toBigDecimal(numberStr), scale, roundingMode);
    }
    
    /**
     * 保留固定位数小数<br>
     * 例如保留四位小数：123.456789 =》 123.4567
     *
     * @param number       数字值
     * @param scale        保留小数位数，如果传入小于0，则默认0
     * @param roundingMode 保留小数的模式 {@link RoundingMode}，如果传入null则默认四舍五入
     * @return 新值
     */
    public static BigDecimal round(BigDecimal number, int scale, RoundingMode roundingMode) {
        if (null == number) {
            number = BigDecimal.ZERO;
        }
        if (scale < 0) {
            scale = 0;
        }
        if (null == roundingMode) {
            roundingMode = RoundingMode.HALF_UP;
        }
        
        return number.setScale(scale, roundingMode);
    }
    
    /**
     * 保留固定位数小数<br>
     * 例如保留四位小数：123.456789 =》 123.4567
     *
     * @param numberStr    数字值的字符串表现形式
     * @param scale        保留小数位数
     * @param roundingMode 保留小数的模式 {@link RoundingMode}
     * @return 新值
     */
    public static String roundStr(String numberStr, int scale, RoundingMode roundingMode) {
        return round(numberStr, scale, roundingMode).toPlainString();
    }
    
    /**
     * 四舍六入五成双计算法
     * <p>
     * 四舍六入五成双是一种比较精确比较科学的计数保留法，是一种数字修约规则。
     * </p>
     *
     * <pre>
     * 算法规则:
     * 四舍六入五考虑，
     * 五后非零就进一，
     * 五后皆零看奇偶，
     * 五前为偶应舍去，
     * 五前为奇要进一。
     * </pre>
     *
     * @param number 需要科学计算的数据
     * @param scale  保留的小数位
     * @return 结果
     */
    public static BigDecimal roundHalfEven(Number number, int scale) {
        return roundHalfEven(toBigDecimal(number), scale);
    }
    
    /**
     * 四舍六入五成双计算法
     * <p>
     * 四舍六入五成双是一种比较精确比较科学的计数保留法，是一种数字修约规则。
     * </p>
     *
     * <pre>
     * 算法规则:
     * 四舍六入五考虑，
     * 五后非零就进一，
     * 五后皆零看奇偶，
     * 五前为偶应舍去，
     * 五前为奇要进一。
     * </pre>
     *
     * @param value 需要科学计算的数据
     * @param scale 保留的小数位
     * @return 结果
     */
    public static BigDecimal roundHalfEven(BigDecimal value, int scale) {
        return round(value, scale, RoundingMode.HALF_EVEN);
    }
    
    /**
     * 保留固定小数位数，舍去多余位数
     *
     * @param number 需要科学计算的数据
     * @param scale  保留的小数位
     * @return 结果
     */
    public static BigDecimal roundDown(Number number, int scale) {
        return roundDown(toBigDecimal(number), scale);
    }
    
    /**
     * 保留固定小数位数，舍去多余位数
     *
     * @param value 需要科学计算的数据
     * @param scale 保留的小数位
     * @return 结果
     */
    public static BigDecimal roundDown(BigDecimal value, int scale) {
        return round(value, scale, RoundingMode.DOWN);
    }
    
    // ------------------------------------------------------------------------------------------- decimalFormat
    
    /**
     * 格式化double<br>
     * 对 {@link DecimalFormat} 做封装<br>
     *
     * @param pattern 格式 格式中主要以 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充，# 表示只要有可能就把数字拉上这个位置。<br>
     *                <ul>
     *                <li>0 =》 取一位整数</li>
     *                <li>0.00 =》 取一位整数和两位小数</li>
     *                <li>00.000 =》 取两位整数和三位小数</li>
     *                <li># =》 取所有整数部分</li>
     *                <li>#.##% =》 以百分比方式计数，并取两位小数</li>
     *                <li>#.#####E0 =》 显示为科学计数法，并取五位小数</li>
     *                <li>,### =》 每三位以逗号进行分隔，例如：299,792,458</li>
     *                <li>光速大小为每秒,###米 =》 将格式嵌入文本</li>
     *                </ul>
     * @param value   值
     * @return 格式化后的值
     */
    public static String decimalFormat(String pattern, double value) {
        Asserts.as(isValid(value), "value is NaN or Infinite!");
        return new DecimalFormat(pattern).format(value);
    }
    
    /**
     * 格式化double<br>
     * 对 {@link DecimalFormat} 做封装<br>
     *
     * @param pattern 格式 格式中主要以 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充，# 表示只要有可能就把数字拉上这个位置。<br>
     *                <ul>
     *                <li>0 =》 取一位整数</li>
     *                <li>0.00 =》 取一位整数和两位小数</li>
     *                <li>00.000 =》 取两位整数和三位小数</li>
     *                <li># =》 取所有整数部分</li>
     *                <li>#.##% =》 以百分比方式计数，并取两位小数</li>
     *                <li>#.#####E0 =》 显示为科学计数法，并取五位小数</li>
     *                <li>,### =》 每三位以逗号进行分隔，例如：299,792,458</li>
     *                <li>光速大小为每秒,###米 =》 将格式嵌入文本</li>
     *                </ul>
     * @param value   值
     * @return 格式化后的值
     */
    public static String decimalFormat(String pattern, long value) {
        return new DecimalFormat(pattern).format(value);
    }
    
    /**
     * 格式化double<br>
     * 对 {@link DecimalFormat} 做封装<br>
     *
     * @param pattern 格式 格式中主要以 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充，# 表示只要有可能就把数字拉上这个位置。<br>
     *                <ul>
     *                <li>0 =》 取一位整数</li>
     *                <li>0.00 =》 取一位整数和两位小数</li>
     *                <li>00.000 =》 取两位整数和三位小数</li>
     *                <li># =》 取所有整数部分</li>
     *                <li>#.##% =》 以百分比方式计数，并取两位小数</li>
     *                <li>#.#####E0 =》 显示为科学计数法，并取五位小数</li>
     *                <li>,### =》 每三位以逗号进行分隔，例如：299,792,458</li>
     *                <li>光速大小为每秒,###米 =》 将格式嵌入文本</li>
     *                </ul>
     * @param value   值，支持BigDecimal、BigInteger、Number等类型
     * @return 格式化后的值
     */
    public static String decimalFormat(String pattern, Object value) {
        return decimalFormat(pattern, value, null);
    }
    
    /**
     * 格式化double<br>
     * 对 {@link DecimalFormat} 做封装<br>
     *
     * @param pattern      格式 格式中主要以 # 和 0 两种占位符号来指定数字长度。0 表示如果位数不足则以 0 填充，# 表示只要有可能就把数字拉上这个位置。<br>
     *                     <ul>
     *                     <li>0 =》 取一位整数</li>
     *                     <li>0.00 =》 取一位整数和两位小数</li>
     *                     <li>00.000 =》 取两位整数和三位小数</li>
     *                     <li># =》 取所有整数部分</li>
     *                     <li>#.##% =》 以百分比方式计数，并取两位小数</li>
     *                     <li>#.#####E0 =》 显示为科学计数法，并取五位小数</li>
     *                     <li>,### =》 每三位以逗号进行分隔，例如：299,792,458</li>
     *                     <li>光速大小为每秒,###米 =》 将格式嵌入文本</li>
     *                     </ul>
     * @param value        值，支持BigDecimal、BigInteger、Number等类型
     * @param roundingMode 保留小数的方式枚举
     * @return 格式化后的值
     */
    public static String decimalFormat(String pattern, Object value, RoundingMode roundingMode) {
        if (value instanceof Number) {
            Asserts.as(isValidNumber((Number) value), "value is NaN or Infinite!");
        }
        final DecimalFormat decimalFormat = new DecimalFormat(pattern);
        if (null != roundingMode) {
            decimalFormat.setRoundingMode(roundingMode);
        }
        return decimalFormat.format(value);
    }
    
    /**
     * 格式化金额输出，每三位用逗号分隔
     *
     * @param value 金额
     * @return 格式化后的值
     */
    public static String decimalFormatMoney(double value) {
        return decimalFormat(",##0.00", value);
    }
    
    /**
     * 格式化百分比，小数采用四舍五入方式
     *
     * @param number 值
     * @param scale  保留小数位数
     * @return 百分比
     */
    public static String formatPercent(double number, int scale) {
        final NumberFormat format = NumberFormat.getPercentInstance();
        format.setMaximumFractionDigits(scale);
        return format.format(number);
    }
    
    // ------------------------------------------------------------------------------------------- isXXX
    
    /**
     * 是否为数字，支持包括：
     *
     * <pre>
     * 1、10进制
     * 2、16进制数字（0x开头）
     * 3、科学计数法形式（1234E3）
     * 4、类型标识形式（123D）
     * 5、正负数标识形式（+123、-234）
     * </pre>
     *
     * @param str 字符串值
     * @return 是否为数字
     */
    public static boolean isNumber(CharSequence str) {
        if (StrUtils.isBlank(str)) {
            return false;
        }
        
        // char[] chars = str.toString().toCharArray();
        final int len = str.length();
        int sz = str.length();
        boolean hasExp = false;
        boolean hasDecPoint = false;
        boolean allowSigns = false;
        boolean foundDigit = false;
        // deal with any possible sign up front
        char c0 = str.charAt(0);
        int start = (c0 == '-' || c0 == '+') ? 1 : 0;
        if (sz > start + 1) {
            if (str.charAt(start) == '0' && (str.charAt(start + 1) == 'x' || str.charAt(start + 1) == 'X')) {
                int i = start + 2;
                if (i == sz) {
                    return false; // str == "0x"
                }
                // checking hex (it can't be anything else)
                for (; i < len; i++) {
                    char ci = str.charAt(i);
                    if ((ci < '0' || ci > '9') && (ci < 'a' || ci > 'f') && (ci < 'A' || ci > 'F')) {
                        return false;
                    }
                }
                return true;
            }
        }
        sz--; // don't want to loop to the last char, check it afterwords
        // for type qualifiers
        int i = start;
        // loop to the next to last char or to the last char if we need another digit to
        // make a valid number (e.g. chars[0..5] = "1234E")
        while (i < sz || (i < sz + 1 && allowSigns && !foundDigit)) {
            char ci = str.charAt(i);
            if (ci >= '0' && ci <= '9') {
                foundDigit = true;
                allowSigns = false;
                
            }
            else if (ci == '.') {
                if (hasDecPoint || hasExp) {
                    // two decimal points or dec in exponent
                    return false;
                }
                hasDecPoint = true;
            }
            else if (ci == 'e' || ci == 'E') {
                // we've already taken care of hex.
                if (hasExp) {
                    // two E's
                    return false;
                }
                if (false == foundDigit) {
                    return false;
                }
                hasExp = true;
                allowSigns = true;
            }
            else if (ci == '+' || ci == '-') {
                if (!allowSigns) {
                    return false;
                }
                allowSigns = false;
                foundDigit = false; // we need a digit after the E
            }
            else {
                return false;
            }
            i++;
        }
        if (i < len) {
            char ci = str.charAt(i);
            if (ci >= '0' && ci <= '9') {
                // no type qualifier, OK
                return true;
            }
            if (ci == 'e' || ci == 'E') {
                // can't have an E at the last byte
                return false;
            }
            if (ci == '.') {
                if (hasDecPoint || hasExp) {
                    // two decimal points or dec in exponent
                    return false;
                }
                // single trailing decimal point after non-exponent is ok
                return foundDigit;
            }
            if (!allowSigns && (ci == 'd' || ci == 'D' || ci == 'f' || ci == 'F')) {
                return foundDigit;
            }
            if (ci == 'l' || ci == 'L') {
                // not allowing L with an exponent
                return foundDigit && !hasExp;
            }
            // last character is illegal
            return false;
        }
        // allowSigns is true iff the val ends in 'E'
        // found digit it to make sure weird stuff like '.' and '1E-' doesn't pass
        return false == allowSigns && foundDigit;
    }
    
    /**
     * 判断String是否是整数<br>
     * 支持10进制
     *
     * @param s String
     * @return 是否为整数
     */
    public static boolean isInteger(String s) {
        if (StrUtils.isBlank(s)) {
            return false;
        }
        try {
            Integer.parseInt(s);
        }
        catch (NumberFormatException e) {
            return false;
        }
        return true;
    }
    
    /**
     * 判断字符串是否是Long类型<br>
     * 支持10进制
     *
     * @param s String
     * @return 是否为{@link Long}类型
     */
    public static boolean isLong(String s) {
        if (StrUtils.isBlank(s)) {
            return false;
        }
        try {
            Long.parseLong(s);
        }
        catch (NumberFormatException e) {
            return false;
        }
        return true;
    }
    
    /**
     * 判断字符串是否是浮点数
     *
     * @param s String
     * @return 是否为{@link Double}类型
     */
    public static boolean isDouble(String s) {
        if (StrUtils.isBlank(s)) {
            return false;
        }
        try {
            Double.parseDouble(s);
        }
        catch (NumberFormatException ignore) {
            return false;
        }
        return s.contains(".");
    }
    
    /**
     * 是否是质数（素数）<br>
     * 质数表的质数又称素数。指整数在一个大于1的自然数中,除了1和此整数自身外,没法被其他自然数整除的数。
     *
     * @param n 数字
     * @return 是否是质数
     */
    public static boolean isPrimes(int n) {
        Asserts.as(n > 1, "The number must be > 1");
        for (int i = 2; i <= Math.sqrt(n); i++) {
            if (n % i == 0) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 从0开始给定范围内的整数列表，步进为1
     *
     * @param stop 结束（包含）
     * @return 整数列表
     */
    public static int[] range(int stop) {
        return range(0, stop);
    }
    
    /**
     * 给定范围内的整数列表，步进为1
     *
     * @param start 开始（包含）
     * @param stop  结束（包含）
     * @return 整数列表
     */
    public static int[] range(int start, int stop) {
        return range(start, stop, 1);
    }
    
    /**
     * 给定范围内的整数列表
     *
     * @param start 开始（包含）
     * @param stop  结束（包含）
     * @param step  步进
     * @return 整数列表
     */
    public static int[] range(int start, int stop, int step) {
        if (start < stop) {
            step = Math.abs(step);
        }
        else if (start > stop) {
            step = -Math.abs(step);
        }
        else {// start == end
            return new int[]{start};
        }
        
        int size = Math.abs((stop - start) / step) + 1;
        int[] values = new int[size];
        int index = 0;
        for (int i = start; (step > 0) ? i <= stop : i >= stop; i += step) {
            values[index] = i;
            index++;
        }
        return values;
    }
    
    /**
     * 将给定范围内的整数添加到已有集合中，步进为1
     *
     * @param start  开始（包含）
     * @param stop   结束（包含）
     * @param values 集合
     * @return 集合
     */
    public static Collection<Integer> appendRange(int start, int stop, Collection<Integer> values) {
        return appendRange(start, stop, 1, values);
    }
    
    /**
     * 将给定范围内的整数添加到已有集合中
     *
     * @param start  开始（包含）
     * @param stop   结束（包含）
     * @param step   步进
     * @param values 集合
     * @return 集合
     */
    public static Collection<Integer> appendRange(int start, int stop, int step, Collection<Integer> values) {
        if (start < stop) {
            step = Math.abs(step);
        }
        else if (start > stop) {
            step = -Math.abs(step);
        }
        else {// start == end
            values.add(start);
            return values;
        }
        
        for (int i = start; (step > 0) ? i <= stop : i >= stop; i += step) {
            values.add(i);
        }
        return values;
    }
    
    // ------------------------------------------------------------------------------------------- others
    
    /**
     * 计算阶乘
     * <p>
     * n! = n * (n-1) * ... * 2 * 1
     * </p>
     *
     * @param n 阶乘起始
     * @return 结果
     */
    public static BigInteger factorial(BigInteger n) {
        if (n.equals(BigInteger.ZERO)) {
            return BigInteger.ONE;
        }
        return factorial(n, BigInteger.ZERO);
    }
    
    /**
     * 计算范围阶乘
     * <p>
     * factorial(start, end) = start * (start - 1) * ... * (end + 1)
     * </p>
     *
     * @param start 阶乘起始（包含）
     * @param end   阶乘结束，必须小于起始（不包括）
     * @return 结果
     */
    public static BigInteger factorial(BigInteger start, BigInteger end) {
        Asserts.nonNull(start, "Factorial start must be not null!");
        Asserts.nonNull(end, "Factorial end must be not null!");
        if (start.compareTo(BigInteger.ZERO) < 0 || end.compareTo(BigInteger.ZERO) < 0) {
            throw new IllegalArgumentException(StrUtils.format(
                    "Factorial start and end both must be > 0, but got start={}, end={}",
                    start,
                    end));
        }
        
        if (start.equals(BigInteger.ZERO)) {
            start = BigInteger.ONE;
        }
        
        if (end.compareTo(BigInteger.ONE) < 0) {
            end = BigInteger.ONE;
        }
        
        BigInteger result = start;
        end = end.add(BigInteger.ONE);
        while (start.compareTo(end) > 0) {
            start = start.subtract(BigInteger.ONE);
            result = result.multiply(start);
        }
        return result;
    }
    
    /**
     * 计算范围阶乘
     * <p>
     * factorial(start, end) = start * (start - 1) * ... * (end + 1)
     * </p>
     *
     * @param start 阶乘起始（包含）
     * @param end   阶乘结束，必须小于起始（不包括）
     * @return 结果
     */
    public static long factorial(long start, long end) {
        // 负数没有阶乘
        if (start < 0 || end < 0) {
            throw new IllegalArgumentException(StrUtils.format(
                    "Factorial start and end both must be >= 0, but got start={}, end={}",
                    start,
                    end));
        }
        if (0L == start || start == end) {
            return 1L;
        }
        if (start < end) {
            return 0L;
        }
        return factorialMultiplyAndCheck(start, factorial(start - 1, end));
    }
    
    /**
     * 计算范围阶乘中校验中间的计算是否存在溢出，factorial提前做了负数和0的校验，因此这里没有校验数字的正负
     *
     * @param a 乘数
     * @param b 被乘数
     * @return 如果 a * b的结果没有溢出直接返回，否则抛出异常
     */
    private static long factorialMultiplyAndCheck(long a, long b) {
        if (a <= Long.MAX_VALUE / b) {
            return a * b;
        }
        throw new IllegalArgumentException(StrUtils.format("Overflow in multiplication: {} * {}", a, b));
    }
    
    /**
     * 计算阶乘
     * <p>
     * n! = n * (n-1) * ... * 2 * 1
     * </p>
     *
     * @param n 阶乘起始
     * @return 结果
     */
    public static long factorial(long n) {
        if (n < 0 || n > 20) {
            throw new IllegalArgumentException(StrUtils.format(
                    "Factorial must have n >= 0 and n <= 20 for n!, but got n = {}",
                    n));
        }
        return FACTORIALS[(int) n];
    }
    
    /**
     * 平方根算法<br>
     * 推荐使用 {@link Math#sqrt(double)}
     *
     * @param x 值
     * @return 平方根
     */
    public static long sqrt(long x) {
        long y = 0;
        long b = (~Long.MAX_VALUE) >>> 1;
        while (b > 0) {
            if (x >= y + b) {
                x -= y + b;
                y >>= 1;
                y += b;
            }
            else {
                y >>= 1;
            }
            b >>= 2;
        }
        return y;
    }
    
    /**
     * 计算组合数，即C(n,m)
     *
     * @param elements 集合元素数
     * @param selects  选取元素数
     * @return 注数
     */
    public static int combination(int elements, int selects) {
        int result;
        result = mathSubNode(elements, selects) / mathNode(elements - selects);
        return result;
    }
    
    /**
     * 最大公约数
     *
     * @param m 第一个值
     * @param n 第二个值
     * @return 最大公约数
     */
    public static int divisor(int m, int n) {
        while (m % n != 0) {
            int temp = m % n;
            m = n;
            n = temp;
        }
        return n;
    }
    
    /**
     * 最小公倍数
     *
     * @param m 第一个值
     * @param n 第二个值
     * @return 最小公倍数
     */
    public static int multiple(int m, int n) {
        return m * n / divisor(m, n);
    }
    
    /**
     * 获得数字对应的二进制字符串
     *
     * @param number 数字
     * @return 二进制字符串
     */
    public static String getBinaryStr(Number number) {
        if (number instanceof Long) {
            return Long.toBinaryString((Long) number);
        }
        else if (number instanceof Integer) {
            return Integer.toBinaryString((Integer) number);
        }
        else {
            return Long.toBinaryString(number.longValue());
        }
    }
    
    /**
     * 二进制转int
     *
     * @param binaryStr 二进制字符串
     * @return int
     */
    public static int binaryToInt(String binaryStr) {
        return Integer.parseInt(binaryStr, 2);
    }
    
    /**
     * 二进制转long
     *
     * @param binaryStr 二进制字符串
     * @return long
     */
    public static long binaryToLong(String binaryStr) {
        return Long.parseLong(binaryStr, 2);
    }
    
    // ------------------------------------------------------------------------------------------- compare
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回小于0的数，x&gt;y返回大于0的数
     * @see Character#compare(char, char)
     */
    public static int compare(char x, char y) {
        return Character.compare(x, y);
    }
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回小于0的数，x&gt;y返回大于0的数
     * @see Double#compare(double, double)
     */
    public static int compare(double x, double y) {
        return Double.compare(x, y);
    }
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回小于0的数，x&gt;y返回大于0的数
     * @see Integer#compare(int, int)
     */
    public static int compare(int x, int y) {
        return Integer.compare(x, y);
    }
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回小于0的数，x&gt;y返回大于0的数
     * @see Long#compare(long, long)
     */
    public static int compare(long x, long y) {
        return Long.compare(x, y);
    }
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回小于0的数，x&gt;y返回大于0的数
     * @see Short#compare(short, short)
     */
    public static int compare(short x, short y) {
        return Short.compare(x, y);
    }
    
    /**
     * 比较两个值的大小
     *
     * @param x 第一个值
     * @param y 第二个值
     * @return x==y返回0，x&lt;y返回-1，x&gt;y返回1
     * @see Byte#compare(byte, byte)
     */
    public static int compare(byte x, byte y) {
        return Byte.compare(x, y);
    }
    
    /**
     * 比较大小，参数1 &gt; 参数2 返回true
     *
     * @param bigNum1 数字1
     * @param bigNum2 数字2
     * @return 是否大于
     */
    public static boolean isGreater(BigDecimal bigNum1, BigDecimal bigNum2) {
        Asserts.nonNull(bigNum1);
        Asserts.nonNull(bigNum2);
        return bigNum1.compareTo(bigNum2) > 0;
    }
    
    /**
     * 比较大小，参数1 &gt;= 参数2 返回true
     *
     * @param bigNum1 数字1
     * @param bigNum2 数字2
     * @return 是否大于等于
     * 0.9
     */
    public static boolean isGreaterOrEqual(BigDecimal bigNum1, BigDecimal bigNum2) {
        Asserts.nonNull(bigNum1);
        Asserts.nonNull(bigNum2);
        return bigNum1.compareTo(bigNum2) >= 0;
    }
    
    /**
     * 比较大小，参数1 &lt; 参数2 返回true
     *
     * @param bigNum1 数字1
     * @param bigNum2 数字2
     * @return 是否小于
     * 0.9
     */
    public static boolean isLess(BigDecimal bigNum1, BigDecimal bigNum2) {
        Asserts.nonNull(bigNum1);
        Asserts.nonNull(bigNum2);
        return bigNum1.compareTo(bigNum2) < 0;
    }
    
    /**
     * 比较大小，参数1&lt;=参数2 返回true
     *
     * @param bigNum1 数字1
     * @param bigNum2 数字2
     * @return 是否小于等于
     * 0.9
     */
    public static boolean isLessOrEqual(BigDecimal bigNum1, BigDecimal bigNum2) {
        Asserts.nonNull(bigNum1);
        Asserts.nonNull(bigNum2);
        return bigNum1.compareTo(bigNum2) <= 0;
    }
    
    /**
     * 检查值是否在指定范围内
     *
     * @param value      值
     * @param minInclude 最小值（包含）
     * @param maxInclude 最大值（包含）
     * @return 经过检查后的值
     */
    public static boolean isIn(final BigDecimal value, final BigDecimal minInclude, final BigDecimal maxInclude) {
        Asserts.nonNull(value);
        Asserts.nonNull(minInclude);
        Asserts.nonNull(maxInclude);
        return isGreaterOrEqual(value, minInclude) && isLessOrEqual(value, maxInclude);
    }
    
    /**
     * 比较大小，值相等 返回true<br>
     * 此方法通过调用{@link Double#doubleToLongBits(double)}方法来判断是否相等<br>
     * 此方法判断值相等时忽略精度的，即0.00 == 0
     *
     * @param num1 数字1
     * @param num2 数字2
     * @return 是否相等
     */
    public static boolean equals(double num1, double num2) {
        return Double.doubleToLongBits(num1) == Double.doubleToLongBits(num2);
    }
    
    /**
     * 比较大小，值相等 返回true<br>
     * 此方法通过调用{@link Float#floatToIntBits(float)}方法来判断是否相等<br>
     * 此方法判断值相等时忽略精度的，即0.00 == 0
     *
     * @param num1 数字1
     * @param num2 数字2
     * @return 是否相等
     */
    public static boolean equals(float num1, float num2) {
        return Float.floatToIntBits(num1) == Float.floatToIntBits(num2);
    }
    
    /**
     * 比较大小，值相等 返回true<br>
     * 此方法修复传入long型数据由于没有本类型重载方法,导致数据精度丢失
     *
     * @param num1 数字1
     * @param num2 数字2
     * @return 是否相等
     */
    public static boolean equals(long num1, long num2) {
        return num1 == num2;
    }
    
    /**
     * 比较大小，值相等 返回true<br>
     * 此方法通过调用{@link BigDecimal#compareTo(BigDecimal)}方法来判断是否相等<br>
     * 此方法判断值相等时忽略精度的，即0.00 == 0
     *
     * @param bigNum1 数字1
     * @param bigNum2 数字2
     * @return 是否相等
     */
    public static boolean equals(BigDecimal bigNum1, BigDecimal bigNum2) {
        //noinspection NumberEquality
        if (bigNum1 == bigNum2) {
            // 如果用户传入同一对象，省略compareTo以提高性能。
            return true;
        }
        if (bigNum1 == null || bigNum2 == null) {
            return false;
        }
        return 0 == bigNum1.compareTo(bigNum2);
    }
    
    /**
     * 比较两个字符是否相同
     *
     * @param c1         字符1
     * @param c2         字符2
     * @param ignoreCase 是否忽略大小写
     * @return 是否相同
     * @see CharUtil#equals(char, char, boolean)
     */
    public static boolean equals(char c1, char c2, boolean ignoreCase) {
        return StrUtils.equals(c1, c2, ignoreCase);
    }
    
    /**
     * 取最小值
     *
     * @param <T>         元素类型
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(Comparable[])
     */
    public static <T extends Comparable<? super T>> T min(T[] numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(long...)
     */
    public static long min(long... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(int...)
     */
    public static int min(int... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(short...)
     */
    public static short min(short... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(double...)
     */
    public static double min(double... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(float...)
     */
    public static float min(float... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最小值
     *
     * @param numberArray 数字数组
     * @return 最小值
     * @see Arrays#min(Comparable[])
     */
    public static BigDecimal min(BigDecimal... numberArray) {
        return Arrays.min(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param <T>         元素类型
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(Comparable[])
     */
    public static <T extends Comparable<? super T>> T max(T[] numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(long...)
     */
    public static long max(long... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(int...)
     */
    public static int max(int... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(short...)
     */
    public static short max(short... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(double...)
     */
    public static double max(double... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(float...)
     */
    public static float max(float... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 取最大值
     *
     * @param numberArray 数字数组
     * @return 最大值
     * @see Arrays#max(Comparable[])
     */
    public static BigDecimal max(BigDecimal... numberArray) {
        return Arrays.max(numberArray);
    }
    
    /**
     * 数字转字符串<br>
     * 调用{@link Number#toString()}，并去除尾小数点儿后多余的0
     *
     * @param number       A Number
     * @param defaultValue 如果number参数为{@code null}，返回此默认值
     * @return A String.
     */
    public static String toStr(Number number, String defaultValue) {
        return (null == number) ? defaultValue : toStr(number);
    }
    
    /**
     * 数字转字符串<br>
     * 调用{@link Number#toString()}或 {@link BigDecimal#toPlainString()}，并去除尾小数点儿后多余的0
     *
     * @param number A Number
     * @return A String.
     */
    public static String toStr(Number number) {
        return toStr(number, true);
    }
    
    /**
     * 数字转字符串<br>
     * 调用{@link Number#toString()}或 {@link BigDecimal#toPlainString()}，并去除尾小数点儿后多余的0
     *
     * @param number               A Number
     * @param isStripTrailingZeros 是否去除末尾多余0，例如5.0返回5
     * @return A String.
     */
    public static String toStr(Number number, boolean isStripTrailingZeros) {
        Asserts.nonNull(number, "Number is null !");
        
        // BigDecimal单独处理，使用非科学计数法
        if (number instanceof BigDecimal) {
            return toStr((BigDecimal) number, isStripTrailingZeros);
        }
        
        Asserts.as(isValidNumber(number), "Number is non-finite!");
        // 去掉小数点儿后多余的0
        String string = number.toString();
        if (isStripTrailingZeros) {
            if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
                while (string.endsWith("0")) {
                    string = string.substring(0, string.length() - 1);
                }
                if (string.endsWith(".")) {
                    string = string.substring(0, string.length() - 1);
                }
            }
        }
        return string;
    }
    
    /**
     * {@link BigDecimal}数字转字符串<br>
     * 调用{@link BigDecimal#toPlainString()}，并去除尾小数点儿后多余的0
     *
     * @param bigDecimal A {@link BigDecimal}
     * @return A String.
     */
    public static String toStr(BigDecimal bigDecimal) {
        return toStr(bigDecimal, true);
    }
    
    /**
     * {@link BigDecimal}数字转字符串<br>
     * 调用{@link BigDecimal#toPlainString()}，可选去除尾小数点儿后多余的0
     *
     * @param bigDecimal           A {@link BigDecimal}
     * @param isStripTrailingZeros 是否去除末尾多余0，例如5.0返回5
     * @return A String.
     */
    public static String toStr(BigDecimal bigDecimal, boolean isStripTrailingZeros) {
        Asserts.nonNull(bigDecimal, "BigDecimal is null !");
        if (isStripTrailingZeros) {
            bigDecimal = bigDecimal.stripTrailingZeros();
        }
        return bigDecimal.toPlainString();
    }
    
    /**
     * 数字转{@link BigDecimal}<br>
     * Float、Double等有精度问题，转换为字符串后再转换<br>
     * null转换为0
     *
     * @param number 数字
     * @return {@link BigDecimal}
     */
    public static BigDecimal toBigDecimal(Number number) {
        if (null == number) {
            return BigDecimal.ZERO;
        }
        
        if (number instanceof BigDecimal) {
            return (BigDecimal) number;
        }
        else if (number instanceof Long) {
            return new BigDecimal((Long) number);
        }
        else if (number instanceof Integer) {
            return new BigDecimal((Integer) number);
        }
        else if (number instanceof BigInteger) {
            return new BigDecimal((BigInteger) number);
        }
        
        // Float、Double等有精度问题，转换为字符串后再转换
        return toBigDecimal(number.toString());
    }
    
    /**
     * 数字转{@link BigDecimal}<br>
     * null或""或空白符转换为0
     *
     * @param numberStr 数字字符串
     * @return {@link BigDecimal}
     */
    public static BigDecimal toBigDecimal(String numberStr) {
        if (StrUtils.isBlank(numberStr)) {
            return BigDecimal.ZERO;
        }
        
        try {
            // 支持类似于 1,234.55 格式的数字
            final Number number = parseNumber(numberStr);
            if (number instanceof BigDecimal) {
                return (BigDecimal) number;
            }
            else {
                return new BigDecimal(number.toString());
            }
        }
        catch (Exception ignore) {
            // 忽略解析错误
        }
        
        return new BigDecimal(numberStr);
    }
    
    /**
     * 数字转{@link BigInteger}<br>
     * null转换为0
     *
     * @param number 数字
     * @return {@link BigInteger}
     */
    public static BigInteger toBigInteger(Number number) {
        if (null == number) {
            return BigInteger.ZERO;
        }
        
        if (number instanceof BigInteger) {
            return (BigInteger) number;
        }
        else if (number instanceof Long) {
            return BigInteger.valueOf((Long) number);
        }
        
        return toBigInteger(number.longValue());
    }
    
    /**
     * 数字转{@link BigInteger}<br>
     * null或""或空白符转换为0
     *
     * @param number 数字字符串
     * @return {@link BigInteger}
     */
    public static BigInteger toBigInteger(String number) {
        return StrUtils.isBlank(number) ? BigInteger.ZERO : new BigInteger(number);
    }
    
    /**
     * 计算等份个数
     *
     * @param total 总数
     * @param part  每份的个数
     * @return 分成了几份
     */
    public static int count(int total, int part) {
        return (total % part == 0) ? (total / part) : (total / part + 1);
    }
    
    /**
     * 空转0
     *
     * @param decimal {@link BigDecimal}，可以为{@code null}
     * @return {@link BigDecimal}参数为空时返回0的值
     */
    public static BigDecimal null2Zero(BigDecimal decimal) {
        
        return decimal == null ? BigDecimal.ZERO : decimal;
    }
    
    /**
     * 如果给定值为0，返回1，否则返回原值
     *
     * @param value 值
     * @return 1或非0值
     */
    public static int zero2One(int value) {
        return 0 == value ? 1 : value;
    }
    
    /**
     * 创建{@link BigInteger}，支持16进制、10进制和8进制，如果传入空白串返回null<br>
     * from Apache Common Lang
     *
     * @param str 数字字符串
     * @return {@link BigInteger}
     */
    public static BigInteger newBigInteger(String str) {
        str = StrUtils.trimToNull(str);
        if (null == str) {
            return null;
        }
        
        int pos = 0; // 数字字符串位置
        int radix = 10;
        boolean negate = false; // 负数与否
        if (str.startsWith("-")) {
            negate = true;
            pos = 1;
        }
        if (str.startsWith("0x", pos) || str.startsWith("0X", pos)) {
            // hex
            radix = 16;
            pos += 2;
        }
        else if (str.startsWith("#", pos)) {
            // alternative hex (allowed by Long/Integer)
            radix = 16;
            pos++;
        }
        else if (str.startsWith("0", pos) && str.length() > pos + 1) {
            // octal; so long as there are additional digits
            radix = 8;
            pos++;
        } // default is to treat as decimal
        
        if (pos > 0) {
            str = str.substring(pos);
        }
        final BigInteger value = new BigInteger(str, radix);
        return negate ? value.negate() : value;
    }
    
    /**
     * 判断两个数字是否相邻，例如1和2相邻，1和3不相邻<br>
     * 判断方法为做差取绝对值判断是否为1
     *
     * @param number1 数字1
     * @param number2 数字2
     * @return 是否相邻
     */
    public static boolean isBeside(long number1, long number2) {
        return Math.abs(number1 - number2) == 1;
    }
    
    /**
     * 判断两个数字是否相邻，例如1和2相邻，1和3不相邻<br>
     * 判断方法为做差取绝对值判断是否为1
     *
     * @param number1 数字1
     * @param number2 数字2
     * @return 是否相邻
     */
    public static boolean isBeside(int number1, int number2) {
        return Math.abs(number1 - number2) == 1;
    }
    
    /**
     * 把给定的总数平均分成N份，返回每份的个数<br>
     * 当除以分数有余数时每份+1
     *
     * @param total     总数
     * @param partCount 份数
     * @return 每份的个数
     */
    public static int partValue(int total, int partCount) {
        return partValue(total, partCount, true);
    }
    
    /**
     * 把给定的总数平均分成N份，返回每份的个数<br>
     * 如果isPlusOneWhenHasRem为true，则当除以分数有余数时每份+1，否则丢弃余数部分
     *
     * @param total               总数
     * @param partCount           份数
     * @param isPlusOneWhenHasRem 在有余数时是否每份+1
     * @return 每份的个数
     */
    public static int partValue(int total, int partCount, boolean isPlusOneWhenHasRem) {
        int partValue = total / partCount;
        if (isPlusOneWhenHasRem && total % partCount > 0) {
            partValue++;
        }
        return partValue;
    }
    
    /**
     * 提供精确的幂运算
     *
     * @param number 底数
     * @param n      指数
     * @return 幂的积
     */
    public static BigDecimal pow(Number number, int n) {
        return pow(toBigDecimal(number), n);
    }
    
    /**
     * 提供精确的幂运算
     *
     * @param number 底数
     * @param n      指数
     * @return 幂的积
     */
    public static BigDecimal pow(BigDecimal number, int n) {
        return number.pow(n);
    }
    
    
    /**
     * 判断一个整数是否是2的幂
     *
     * @param n 待验证的整数
     * @return 如果n是2的幂返回true, 反之返回false
     */
    public static boolean isPowerOfTwo(long n) {
        return (n > 0) && ((n & (n - 1)) == 0);
    }
    
    /**
     * 解析转换数字字符串为int型数字，规则如下：
     *
     * <pre>
     * 1、0x开头的视为16进制数字
     * 2、0开头的忽略开头的0
     * 3、其它情况按照10进制转换
     * 4、空串返回0
     * 5、.123形式返回0（按照小于0的小数对待）
     * 6、123.56截取小数点之前的数字，忽略小数部分
     * </pre>
     *
     * @param number 数字，支持0x开头、0开头和普通十进制
     * @return int
     * @throws NumberFormatException 数字格式异常
     */
    public static int parseInt(String number) throws NumberFormatException {
        if (StrUtils.isBlank(number)) {
            return 0;
        }
        
        if (StrUtils.containsIgnoreCase(number, "E")) {
            // 科学计数法忽略支持，科学计数法一般用于表示非常小和非常大的数字，这类数字转换为int后精度丢失，没有意义。
            throw new NumberFormatException(StrUtils.format("Unsupported int format: [{}]", number));
        }
        
        if (StrUtils.startsWithIgnoreCase(number, "0x")) {
            // 0x04表示16进制数
            return Integer.parseInt(number.substring(2), 16);
        }
        
        try {
            return Integer.parseInt(number);
        }
        catch (NumberFormatException e) {
            return parseNumber(number).intValue();
        }
    }
    
    /**
     * 解析转换数字字符串为long型数字，规则如下：
     *
     * <pre>
     * 1、0x开头的视为16进制数字
     * 2、0开头的忽略开头的0
     * 3、空串返回0
     * 4、其它情况按照10进制转换
     * 5、.123形式返回0（按照小于0的小数对待）
     * 6、123.56截取小数点之前的数字，忽略小数部分
     * </pre>
     *
     * @param number 数字，支持0x开头、0开头和普通十进制
     * @return long
     */
    public static long parseLong(String number) {
        if (StrUtils.isBlank(number)) {
            return 0L;
        }
        
        if (number.startsWith("0x")) {
            // 0x04表示16进制数
            return Long.parseLong(number.substring(2), 16);
        }
        
        try {
            return Long.parseLong(number);
        }
        catch (NumberFormatException e) {
            return parseNumber(number).longValue();
        }
    }
    
    /**
     * 解析转换数字字符串为long型数字，规则如下：
     *
     * <pre>
     * 1、0开头的忽略开头的0
     * 2、空串返回0
     * 3、其它情况按照10进制转换
     * 4、.123形式返回0.123（按照小于0的小数对待）
     * </pre>
     *
     * @param number 数字，支持0x开头、0开头和普通十进制
     * @return long
     */
    public static float parseFloat(String number) {
        if (StrUtils.isBlank(number)) {
            return 0f;
        }
        
        try {
            return Float.parseFloat(number);
        }
        catch (NumberFormatException e) {
            return parseNumber(number).floatValue();
        }
    }
    
    /**
     * 解析转换数字字符串为long型数字，规则如下：
     *
     * <pre>
     * 1、0开头的忽略开头的0
     * 2、空串返回0
     * 3、其它情况按照10进制转换
     * 4、.123形式返回0.123（按照小于0的小数对待）
     * </pre>
     *
     * @param number 数字，支持0x开头、0开头和普通十进制
     * @return long
     */
    public static double parseDouble(String number) {
        if (StrUtils.isBlank(number)) {
            return 0D;
        }
        
        try {
            return Double.parseDouble(number);
        }
        catch (NumberFormatException e) {
            return parseNumber(number).doubleValue();
        }
    }
    
    /**
     * 将指定字符串转换为{@link Number} 对象<br>
     * 此方法不支持科学计数法
     *
     * @param numberStr Number字符串
     * @return Number对象
     * @throws NumberFormatException 包装了{@link ParseException}，当给定的数字字符串无法解析时抛出
     */
    public static Number parseNumber(String numberStr) throws NumberFormatException {
        if (StrUtils.startsWithIgnoreCase(numberStr, "0x")) {
            // 0x04表示16进制数
            return Long.parseLong(numberStr.substring(2), 16);
        }
        
        try {
            final NumberFormat format = NumberFormat.getInstance();
            if (format instanceof DecimalFormat) {
                // issue#1818@Github
                // 当字符串数字超出double的长度时，会导致截断，此处使用BigDecimal接收
                ((DecimalFormat) format).setParseBigDecimal(true);
            }
            return format.parse(numberStr);
        }
        catch (ParseException e) {
            final NumberFormatException nfe = new NumberFormatException(e.getMessage());
            nfe.initCause(e);
            throw nfe;
        }
    }
    
    /**
     * int值转byte数组，使用大端字节序（高位字节在前，低位字节在后）<br>
     * 见：<a href="http://www.ruanyifeng.com/blog/2016/11/byte-order.html">http://www.ruanyifeng.com/blog/2016/11/byte-order.html</a>
     *
     * @param value 值
     * @return byte数组
     */
    public static byte[] toBytes(int value) {
        final byte[] result = new byte[4];
        
        result[0] = (byte) (value >> 24);
        result[1] = (byte) (value >> 16);
        result[2] = (byte) (value >> 8);
        result[3] = (byte) (value /* >> 0 */);
        
        return result;
    }
    
    /**
     * byte数组转int，使用大端字节序（高位字节在前，低位字节在后）<br>
     * 见：<a href="http://www.ruanyifeng.com/blog/2016/11/byte-order.html">http://www.ruanyifeng.com/blog/2016/11/byte-order.html</a>
     *
     * @param bytes byte数组
     * @return int
     */
    public static int toInt(byte[] bytes) {
        return (bytes[0] & 0xff) << 24//
                | (bytes[1] & 0xff) << 16//
                | (bytes[2] & 0xff) << 8//
                | (bytes[3] & 0xff);
    }
    
    /**
     * 以无符号字节数组的形式返回传入值。
     *
     * @param value 需要转换的值
     * @return 无符号bytes
     */
    public static byte[] toUnsignedByteArray(BigInteger value) {
        byte[] bytes = value.toByteArray();
        
        if (bytes[0] == 0) {
            byte[] tmp = new byte[bytes.length - 1];
            System.arraycopy(bytes, 1, tmp, 0, tmp.length);
            
            return tmp;
        }
        
        return bytes;
    }
    
    /**
     * 以无符号字节数组的形式返回传入值。
     *
     * @param length bytes长度
     * @param value  需要转换的值
     * @return 无符号bytes
     */
    public static byte[] toUnsignedByteArray(int length, BigInteger value) {
        byte[] bytes = value.toByteArray();
        if (bytes.length == length) {
            return bytes;
        }
        
        int start = bytes[0] == 0 ? 1 : 0;
        int count = bytes.length - start;
        
        if (count > length) {
            throw new IllegalArgumentException("standard length exceeded for value");
        }
        
        byte[] tmp = new byte[length];
        System.arraycopy(bytes, start, tmp, tmp.length - count, count);
        return tmp;
    }
    
    /**
     * 无符号bytes转{@link BigInteger}
     *
     * @param buf buf 无符号bytes
     * @return {@link BigInteger}
     */
    public static BigInteger fromUnsignedByteArray(byte[] buf) {
        return new BigInteger(1, buf);
    }
    
    /**
     * 无符号bytes转{@link BigInteger}
     *
     * @param buf    无符号bytes
     * @param off    起始位置
     * @param length 长度
     * @return {@link BigInteger}
     */
    public static BigInteger fromUnsignedByteArray(byte[] buf, int off, int length) {
        byte[] mag = buf;
        if (off != 0 || length != buf.length) {
            mag = new byte[length];
            System.arraycopy(buf, off, mag, 0, length);
        }
        return new BigInteger(1, mag);
    }
    
    /**
     * 检查是否为有效的数字<br>
     * 检查Double和Float是否为无限大，或者Not a Number<br>
     * 非数字类型和Null将返回true
     *
     * @param number 被检查类型
     * @return 检查结果，非数字类型和Null将返回true
     */
    public static boolean isValidNumber(Number number) {
        if (null == number) {
            return false;
        }
        if (number instanceof Double) {
            return (!((Double) number).isInfinite()) && (!((Double) number).isNaN());
        }
        else if (number instanceof Float) {
            return (!((Float) number).isInfinite()) && (!((Float) number).isNaN());
        }
        return true;
    }
    
    /**
     * 检查是否为有效的数字<br>
     * 检查double否为无限大，或者Not a Number（NaN）<br>
     *
     * @param number 被检查double
     * @return 检查结果
     */
    public static boolean isValid(double number) {
        return !(Double.isNaN(number) || Double.isInfinite(number));
    }
    
    /**
     * 检查是否为有效的数字<br>
     * 检查double否为无限大，或者Not a Number（NaN）<br>
     *
     * @param number 被检查double
     * @return 检查结果
     */
    public static boolean isValid(float number) {
        return !(Float.isNaN(number) || Float.isInfinite(number));
    }
    
    /**
     * 计算数学表达式的值，只支持加减乘除和取余<br>
     * 如：
     * <pre class="code">
     *   calculate("(0*1--3)-5/-4-(3*(-2.13))") -》 10.64
     * </pre>
     *
     * @param expression 数学表达式
     * @return 结果
     */
    public static double calculate(String expression) {
        return Calculator.conversion(expression);
    }
    
    /**
     * Number值转换为double<br>
     * float强制转换存在精度问题，此方法避免精度丢失
     *
     * @param value 被转换的float值
     * @return double值
     */
    public static double toDouble(Number value) {
        if (value instanceof Float) {
            return Double.parseDouble(value.toString());
        }
        else {
            return value.doubleValue();
        }
    }
    
    /**
     * 检查是否为奇数<br>
     *
     * @param num 被判断的数值
     * @return 是否是奇数
     */
    public static boolean isOdd(int num) {
        return (num & 1) == 1;
    }
    
    /**
     * 检查是否为偶数<br>
     *
     * @param num 被判断的数值
     * @return 是否是偶数
     */
    public static boolean isEven(int num) {
        return !isOdd(num);
    }
    
    // ------------------------------------------------------------------------------------------- Private method start
    private static int mathSubNode(int selectNum, int minNum) {
        if (selectNum == minNum) {
            return 1;
        }
        else {
            return selectNum * mathSubNode(selectNum - 1, minNum);
        }
    }
    
    private static int mathNode(int selectNum) {
        if (selectNum == 0) {
            return 1;
        }
        else {
            return selectNum * mathNode(selectNum - 1);
        }
    }
    // ------------------------------------------------------------------------------------------- Private method end
    
    /**
     * 数值*通配符解析 ，如：8 * 64k * 155Mb * 1gb
     *
     * @param str
     * @param defValue 默认值
     * @return
     * @throws NumberFormatException 转换错误是返回
     */
    public static BigDecimal fromValue(String str) throws NumberFormatException {
        return fromValue(str, (String) null);
    }
    
    /**
     * 数值*通配符解析 ，如：8 * 64k * 155Mb * 1gb
     *
     * @param str
     * @param defValue 默认值
     * @return
     * @throws NumberFormatException 转换错误是返回
     */
    public static BigDecimal fromValue(String str, String defValue) throws NumberFormatException {
        
        if (Validates.isBlank(str)) {str = defValue;}
        
        if (Validates.isBlank(str)) {return null;}
        
        List<BigDecimal> ls = new ArrayList<BigDecimal>(4);
        
        String[] arr = str.replaceAll(",", "").split("\\*");
        List<String> units = SIZE_UNIT_CONF.keySet()
                .stream()
                .filter(item -> item.length() == 1)
                .collect(Collectors.toList());
        op:
        for (String item : arr) {
            item = StrUtils.trimToNull(item);
            if (item == null) continue;
            
            if (Validates.isFloat(item)) {
                ls.add(new BigDecimal(item));
                continue;
            }
            
            item = item.toLowerCase();
            BigDecimal one = BigDecimal.ONE;
            op_unit:
            for (int i = 0; i < units.size(); i++) {
                String unit = units.get(i);
                int idx = -1;
                Long unit_val = null;
                if ((idx = item.indexOf(unit)) != -1) {
                    unit = item.substring(idx);
                    item = StrUtils.trim(item.substring(0, idx));
                    if (item.isEmpty() || !Validates.isFloat(item) || (unit_val = SIZE_UNIT_CONF.get(unit)) == null) {
                        throw new NumberFormatException("The parameter format [" + str + "] is incorrect!");
                    }
                    
                    ls.add((item.isEmpty() ? one : new BigDecimal(item)).multiply(new BigDecimal(unit_val)));
                    break op_unit;
                }
            }
        }
        // 参数格式不正确
        if (ls.isEmpty()) {
            throw new NumberFormatException("The parameter format [" + str + "] is incorrect!");
        }
        
        BigDecimal ret = BigDecimal.ONE;
        for (int i = 1; i < ls.size(); i++) {
            ret = ret.multiply(ls.get(i));
        }
        return ret;
    }
    
    public static BigDecimal fromValue(String str, BigDecimal defValue) throws NumberFormatException {
        if (str == null) return defValue;
        BigDecimal ret = fromValue(str, (String) null);
        return ret == null ? defValue : ret;
    }
    
    public static BigDecimal fromValue(String str, BigDecimal min, BigDecimal max, BigDecimal defValue) throws
                                                                                                        NumberFormatException {
        BigDecimal ret = fromValue(str, (String) null);
        if (ret == null) ret = defValue;
        if (ret == null) return null;
        if (min != null && ret.compareTo(min) < 0) return min;
        if (max != null && ret.compareTo(max) > 0) return max;
        return ret;
    }
    
    public static BigDecimal fromValue(String str, BigDecimal min, BigDecimal max) throws NumberFormatException {
        BigDecimal ret = fromValue(str, (String) null);
        if (ret == null) return null;
        if (min != null && ret.compareTo(min) < 0) return min;
        if (max != null && ret.compareTo(max) > 0) return max;
        return ret;
    }
    
    
    public static int fromValue(String str, int min, int max, int defValue) throws NumberFormatException {
        int ret = fromValue(str, String.valueOf(defValue)).intValue();
        if (ret < min) return min;
        if (ret < max) return max;
        return ret;
    }
    
    public static int fromValue(String str, int min, int max) throws NumberFormatException {
        int ret = fromValue(str, "0").intValue();
        if (ret < min) return min;
        if (ret < max) return max;
        return ret;
    }
    
    
    public static long fromValue(String str, long min, long max, long defValue) throws NumberFormatException {
        long ret = fromValue(str, String.valueOf(defValue)).intValue();
        if (ret < min) return min;
        if (ret < max) return max;
        return ret;
    }
    
    public static long fromValue(String str, long min, long max) throws NumberFormatException {
        long ret = fromValue(str, "0").longValue();
        if (ret < min) return min;
        if (ret < max) return max;
        return ret;
    }
    
    /**
     * 计算比百分比 四舍五入
     *
     * @param oldValue
     * @param newValue
     * @param scale
     * @return
     */
    public static double growthRateRound(Number oldValue, Number newValue, int scale) {
        return growthRate(oldValue, newValue, scale, 0);
    }
    
    /**
     * 计算比百分比 向上取整
     *
     * @param oldValue
     * @param newValue
     * @param scale
     * @return
     */
    public static double growthRateCeil(Number oldValue, Number newValue, int scale) {
        return growthRate(oldValue, newValue, scale, 1);
    }
    
    /**
     * 计算比百分比 向下取整
     *
     * @param oldValue
     * @param newValue
     * @param scale
     * @return
     */
    public static double growthRateFloor(Number oldValue, Number newValue, int scale) {
        return growthRate(oldValue, newValue, scale, 1);
    }
    
    private static double growthRate(Number oldVal, Number newVal, int scale, int mode) {
        if (oldVal == null) oldVal = 0;
        if (newVal == null) newVal = 0;
        Double oldValue = oldVal.doubleValue();
        Double newValue = newVal.doubleValue();
        if (oldValue == 0) return newValue > 0 ? 100 : newValue == 0 ? 0 : -100;
        double rawGrowth = (newValue - oldValue) / oldValue * 100;
        // 负数基准时反转符号，并限制最大增长率
        double adjustedGrowth = (oldValue > 0) ? rawGrowth : -rawGrowth;
        double ss = Math.pow(10, scale);
        switch (mode) {
            case 1: // 向上取整
                return Math.ceil((adjustedGrowth * ss)) / ss;
            case 2: // 向下取整
                return Math.floor((adjustedGrowth * ss)) / ss;
            case 0: // 四舍五入
            default:
                return Math.round((adjustedGrowth * ss)) / ss;
        }
    }
}
